package com.fafi.selfmvc.controller;

import com.fafi.selfmvc.validator.AddressValidator;
import com.fafi.selfmvc.validator.CustomerValidator;
import com.fafi.selfmvc.validator.MyBeanValidator;
import com.fafi.selfmvc.vo.Address;
import com.fafi.selfmvc.vo.Customer;
import com.fafi.selfmvc.vo.MyBean;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.DataBinder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Controller
@RequestMapping("one") //二级映射在类上和方法上同时注解@RequestMapping，相当于地址栏里有两级的地址 //如上注解后，映射地址为：http://localhost:8080/xx/one/two
public class TestController {

	static Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);

	@RequestMapping("sayHello")
	@ResponseBody
	public ModelAndView sayHello(int age, String name) {
		ModelAndView mav = new ModelAndView();
		MyBean bean = new MyBean(age, name);

		logger.info("请求参数：{}", bean.toString());

		mav.addObject("myBean", bean);
		mav.setViewName("sayHello");
		System.out.println(bean.toString());

		DataBinder binder = new DataBinder(bean);
		binder.setValidator(new MyBeanValidator());
		// validate the target object
		binder.validate();
		// get BindingResult that includes any validation errors
		BindingResult results = binder.getBindingResult();
		logger.info("results:{}", results);

		Address address = new Address();
		address.setLocation("london streat");

		Customer customer = new Customer();
		customer.setFirstName("tom");
		customer.setSurname("cruise");
		customer.setAddress(address);

		binder = new DataBinder(customer);
		binder.setValidator(new CustomerValidator(new AddressValidator()));
		binder.validate();
		results = binder.getBindingResult();
		logger.info("customer results:{}", results);

		return mav;
	}

	@RequestMapping("ajaxAge")
	@ResponseBody
	public MyBean ajaxAge(int age, String name) {
		MyBean bean = new MyBean(age, name);
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return bean;
	}
	/**
	 * 当返回值是String，并且方法上方有@ResponseBody注解时，
	 * 返回的字符串将不在被解析为springmvc的视图(即jsp文件)，
	 * 会被直接以字符串展示在浏览器里
	 * @return
	 */
	@RequestMapping("retstr")
	@ResponseBody
	public String retStr() {
		return "retstr";
	}

	//有method属性作为对提价类型的选择接受
	//如果没有指定method，则默认为所有请求类型都接受
	@RequestMapping(value="postSample",method={ RequestMethod.POST})
	public String postSample() {
		return "postSample";
	}

	/**
	 * 1. 使用RequestMapping注解来映射请求的URL，写在方法上面，一个请求对应一个方法
	 * 2. 返回值会通过视图解析器解析为实际的物理视图, 会做如下解析
	 * 通过prefix+returnVal+suffix 这样的方式得到实际的物理视图，然后会转发操作
	 * "/WEB-INF/pages/sayHello.jsp"
	 *
	 * 并且请求的参数必须包含id=123，必须包含name，不能包含age
	 * //根据上述规则此地址合法：http://localhost:8080/xx?id=123&name=abc
	 *
	 * //新建一个标准的PO，同时当前类的属性名应该跟前台代码里的KEY对应上
	 * public class PO{
	 *     private String name;//和key值一样
	 *     private Stirng price;//和key值一样
	 *     //省略各自的set get
	 * }
	 * //后台响应上面ajax的post请求的代码
	 * //通过PO里的“name”和“price”属性名和前台js代码里的key相同，把“shouji”和“8888”传到hc方法里
	 * //问号传值的方式同样适用    ?name=shoji&price=8888
	 *
	 */
	@RequestMapping(value="sayHelloBystr",params={"id=123","name","!age"})
	public String sayHelloBystr(String name) {
		System.out.println(name);
		return "sayHello";
	}

	@RequestMapping(value="sayHelloBystrOne")
	public String sayHelloBystrOne(MyBean bean) {
		System.out.println(bean.getName());
		return "sayHello";
	}

	/**
	 * //后台响应上面ajax的post请求的代码
	 * //通过注解里的“name”和“price”参数名和前台js代码里的key相同，把“shouji”和“8888”传到hc方法里
	 * //问号传值的方式同样适用    ?name=shoji&price=8888
	 * @param p1
	 * @param p2
	 * @return
	 */
	@RequestMapping(value="sayHelloBystrTwo")
	public String sayHelloBystrTwo(@RequestParam("name") String p1, @RequestParam("age") String p2) {
		System.out.println(p1+":"+p2);
		return "sayHello";
	}

	@RequestMapping(value="sayHelloBystrThree/name/{p1}/age/{p2}")
	public String sayHelloBystrThree(@PathVariable String p1, @PathVariable String p2) {
		System.out.println(p1+":"+p2);
		return "sayHello";
	}

	//response.sendRedirect重定向跳转
	@RequestMapping(value="testredirect",method = { RequestMethod.POST, RequestMethod.GET })
	public ModelAndView testredirect(HttpServletResponse response) throws IOException {
		response.sendRedirect("sayHello?age=12");
		return null;
	}

	//ViewResolver直接跳转
	@RequestMapping(value="testredirect1",method = { RequestMethod.POST, RequestMethod.GET })
	public  String testredirect1(HttpServletResponse response){
		return "redirect:sayHello?age=12";
	}

	/**
	 * 使用RedirectAttributes的addAttribute方法传递参数会跟随在URL后面，如上代码即为http:/index.action?test=51gjie
	 *
	 * 使用addFlashAttribute不会跟随在URL后面，会把该参数值暂时保存于session，待重定向url获取该参数后从session中移除，这里的redirect必须是方法映射路径，jsp无效。你会发现redirect后的jsp页面中b只会出现一次，刷新后b再也不会出现了，这验证了上面说的，b被访问后就会从session中移除。对于重复提交可以使用此来完成.
	 *
	 * spring mvc设置下RequestMappingHandlerAdapter 的ignoreDefaultModelOnRedirect=true,这样可以提高效率，避免不必要的检索。
	 * @param model
	 * @param attr
	 * @return
	 */
	@RequestMapping("testredirect2")
	public String testredirect2(Model model, RedirectAttributes attr) {
		attr.addAttribute("age", "12");//跳转地址带上test参数
		attr.addFlashAttribute("name", "51gjie");//跳转地址不带上name参数
		return "redirect:sayHello";
	}
	//ModelAndView重定向
	@RequestMapping(value="/restredirect3",method = { RequestMethod.POST, RequestMethod.GET })
	public  ModelAndView restredirect3(String userName){
		ModelAndView  model = new ModelAndView("redirect:sayHello?age=3");
		return model;
	}

	/**
	 * 1, redirect重定向可以跳转到任意服务器，可以用在系统间的跳转。
	 * 2, Spring MVC中redirect重定向，参数传递可以直接拼接url也可以使用RedirectAttributes来处理，由于是不同的请求，重定向传递的参数会在地址栏显示，所以传递时要对中文编码进行处理。
	 * @param name
	 * @param age
	 * @return
	 */
	@RequestMapping(value="/toredirect4",method = { RequestMethod.POST, RequestMethod.GET })
	public  ModelAndView toredirect4(String name, int age){
		ModelAndView  model = new ModelAndView("sayHello");
		MyBean bean = new MyBean(age, name);
		model.addObject("myBean", bean);
		//把userName参数带入到controller的RedirectAttributes
		//最终地址为http://localhost:8080/example/one/toredirect4?name=%273fe%27&&age=12
		return model;
	}

	@RequestMapping(value="/ggg",method = { RequestMethod.POST, RequestMethod.GET })
	public void ggg(HttpServletRequest req, HttpServletResponse rep) {
		//标准servlet里怎么写，这段代码就怎么写
		System.out.println(req.getRequestURI());
	}

	@RequestMapping("login")
	public String GotoLogin() {
		return "login";
	}

	@RequestMapping("upload")
	public String GotoUpload() {
		return "upload";
	}

	@RequestMapping("selfentity")
	public ResponseEntity<List<MyBean>> Gotoentity(MyBean bean) {
		if (bean.getName() != null) {
			List<MyBean> list = new ArrayList<>();
			list.add(bean);
			return ResponseEntity.ok(list);
		}
		return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
	}
	//////////////////ajax//////////////
	//参照sayHelloBystrOne
	@RequestMapping("tm")
	@ResponseBody
	public MyBean tm(@RequestBody  MyBean byq2){
		System.out.println(byq2.getName());
		System.out.println(byq2.getAge());
		//System.out.println(name);
		//System.out.println(age);
		//MyBean myBean = new MyBean(age,name);
		return byq2;
	}

	@RequestMapping("tm1")
	public String tm1(@RequestBody  MyBean byq2){
		System.out.println(byq2.getName());
		System.out.println(byq2.getAge());
		//System.out.println(name);
		//System.out.println(age);
		//MyBean myBean = new MyBean(age,name);
		return "success";
	}


	@RequestMapping("nullpointer")
	@ResponseBody
	public MyBean nullpointer(MyBean byq2){
		MyBean bean = null;
		bean.getAge();
		return byq2;
	}

	@RequestMapping("arithmetic")
	@ResponseBody
	public MyBean arithmetic(MyBean byq2){
		int j = 0;
		int i = 5 / j;
		return byq2;
	}

	@RequestMapping("selfioexception")
	@ResponseBody
	public MyBean selfioexception(MyBean byq2) throws IOException {
		throw new  IOException("dsd");
	}

	@ExceptionHandler(value={java.lang.NullPointerException.class})
	public ModelAndView nullPointerExceptionHandler(Exception e) {
		ModelAndView mv = new ModelAndView();
		mv.addObject("error",e.toString()+"--controller类中");
		mv.setViewName("error");
		return mv;
	}
}
